/**
 * @project_name thread
 * @package_name com.gxwz.thread
 * @file_name SynchronizedLock4DifferentCodeBalk.java
 */
package com.gxwz.thread;

/**
 * 同步锁； 如果一份共享的数据要同步，要加锁，应该加在哪里呢？？？ 一般我们会认为应该直接加在共享的资源上，但是实际上，在程序中我们无法将锁加在
 * 共享的实例变量上，只能加在要共享资源的代码块上； 使用synchronized关键字 synchronized(lock) { //.. }
 * 必须要注意的是这里的同步锁lock必须是在内存中是同一个内存地址的对象
 * 
 * 此例演示不同代码块共享同一个资源
 * @author chendequan
 * @email 1527254027@qq.com
 * @datetime 2013-9-5 上午01:34:23
 * 
 */
public class SynchronizedLock4DifferentCodeBalk {
	public static void main(String[] args) {
		new SynchronizedLock4DifferentCodeBalk().init();
	}

	/**
	 * @datetime 2013-9-5 上午01:39:15
	 */
	private void init() {
		/*
		 * 两个线程同时使用了这个对象
		 */
		final Printer printer = new Printer();

//		线程1 调用Printer的print1方法
		new Thread(new Runnable() {
			/*
			 * (non-Javadoc)
			 * 
			 * @see java.lang.Runnable#run()
			 */
			@Override
			public void run() {
				while (true) {
					try {
						Thread.sleep(20);
					} catch (Exception e) {
						e.printStackTrace();
					}
					printer.print1("123456789");
				}
			}
		}).start();

//		线程2 调用Printer的Printer2方法
		new Thread(new Runnable() {
			/*
			 * (non-Javadoc)
			 * 
			 * @see java.lang.Runnable#run()
			 */
			@Override
			public void run() {
				while (true) {
					try {
						Thread.sleep(20);
					} catch (Exception e) {
						e.printStackTrace();
					}
					printer.print2("987654321");
				}
			}
		}).start();
	}


	/**
	 * 虽然两个线程调用的是不同的方法，但都是使用同一个对象去调用类的方法。
	 * 同样引起资源共享问题，仍然需要同步锁
	 */
	// 内部类
	class Printer {

		/**
		 * @datetime 2013-9-5 上午01:41:47
		 * @param string
		 */
		public void print1(String msg) {
			int len = msg.length();

//			  没加synchronized关键字时结果如下：
//			123456789
//			987654321
//			987654321
//			123456789
//			987654123456789
//			321
//			987654321
//			123456789
//			987654321
//			123456789
//			987654321123456789
//
//			123456789
//			987654321
//			987654321
//			123456789			
//			解析的字符出现冲突，不能作为一个整体输出；
//			=================================
//			加了synchronized关键字后。结果如下：
//			但是只给print1方法加同步仍然会出现问题。结果如下：
//			123456789987654321
//
//			987654321
//			123456789
//			987654321
//			123456789
//			987654321
//			123456789
//			98765431221
//			3456789
//			912345687654321
//			---------------必须给调用的两个方法都加同步锁
//			987654321
//			123456789
//			987654321
//			123456789
//			123456789
//			987654321
//			987654321
//			123456789
//			987654321
//			123456789

//			每次解析的字符串可以作为一个整体解析，因为解析的循环再同步代码块之内
//			当有个线程使用者Printer对象是另一个线程只能等待
			
			synchronized (this) {  //this代表的就是Printer本类对象
				for (int i = 0; i < len; i++) {
					System.out.print(msg.charAt(i));
				}
				System.out.println();
			}
		}

		public void print2(String msg) {
			int len = msg.length();
			
			synchronized (this) {  //this代表的就是Printer本类对象
				for (int i = 0; i < len; i++) {
					System.out.print(msg.charAt(i));
				}
				System.out.println();
			}
		}
	}
}
